/*
 * @Description:
 * @Author: fhw
 * @Date: 2022-08-02 14:39:45
 */
import { forwardRef, HttpException, HttpStatus, Inject, Injectable, UseFilters } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { WebSocketGateway, WebSocketServer } from '@nestjs/websockets'
import { equals, isEmpty, isNil } from 'ramda'
import { UserChatRecord } from 'src/chat-record/entities/user-chat-record.entity'
import { HistorySession } from 'src/history-session/entities/history-session.entities'
import { ConfigService } from 'src/socket/config/config.service'
import { throwHttp } from 'src/utlis'
import { Between, Connection, Repository } from 'typeorm'
import { ChatUserService } from '../chat_user/chat_user.service'
import { HttpExceptionFilter } from '../http-exception.filter'
import { AddChatUserFriendsDto, ApplyForVerificationDto, DelChatUserFriendsDto, DeleteFriendsVerificationDto, GetUserFriendsListDto, UpdateFriendsLatestNewsDto, UpdateRemarksDto } from './dto/chat_user_friends'
import { ChatUserFriend } from './entities/chat_user_friend.entity'

@Injectable()
@WebSocketGateway()
export class ChatUserFriendsService {
  @WebSocketServer() server: any
  constructor(
    @InjectRepository(ChatUserFriend)
    private chatUserFriendRepository: Repository<ChatUserFriend>,
    @Inject(forwardRef(() => ChatUserService))
    private readonly chatUserService: ChatUserService,
    @Inject(forwardRef(() => ConfigService))
    public readonly configService: ConfigService,
    private readonly connection: Connection,
  ) { }
  @UseFilters(new HttpExceptionFilter())
  async getUserFriendsList(params: GetUserFriendsListDto) {
    try {
      const { userId, friendsId, status, createTimeEnd, createTimeStart } = params
      const where: GetUserFriendsListDto = {
        userId, friendsId, status, del: '1'
      }
      // 时间筛选
      if (!isNil(createTimeStart) && isNil(createTimeEnd)) {
        where.createDate = Between(createTimeStart, createTimeEnd);
      }
      const data = await this.chatUserFriendRepository.find({
        where,
        skip: 0,
        take: 999999,
        order: { createDate: 'DESC' },
        select: ['id', 'userId', 'friendsId', 'del', 'verification', 'createDate', 'status', 'source'],
        cache: true,
      });
      return data.filter(item => item.friends.del === 1)
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 添加好友
  @UseFilters(new HttpExceptionFilter())
  async addChatUserFriends(params: AddChatUserFriendsDto): Promise<{
    message: string
    success: boolean
  }> {
    // 获取连贯并创立新的queryRunner
    const queryRunner = this.connection.createQueryRunner();
    // 应用咱们的新queryRunner建设真正的数据库连
    await queryRunner.connect();
    // 开始事务
    await queryRunner.startTransaction();
    try {
      const { friendsId, userId, verification } = params
      if (equals(friendsId, userId)) {
        throwHttp('添加id错误，无法添加自己为好友')
        return
      }
      const user = await this.chatUserService.getUserInfo({
        id: userId,
      })
      const friends = await this.chatUserService.getUserInfo({
        id: friendsId,
      })
      await this.chatUserService.getUserInfo({ id: friendsId })
      // 判断是否添加
      const friendData = await this.chatUserFriendRepository.findOne({
        where: { friendsId, userId: user.id as number },
      })
      if (!isNil(friendData)) {
        const { status } = friendData
        // 已通过好友限制重复添加
        if (equals(status, 1)) {
          throwHttp('该好友已经添加')
          return
        }
        return await this.updateChatUserFriendsStatus(params)
      }

      // 好友记录
      const friend = new ChatUserFriend()
      friend.friendsId = userId
      friend.friends = user
      friend.user = friends
      friend.userId = friendsId
      friend.status = 0
      friend.verification = verification
      friend.del = '1'
      //应用事务保留到副表
      const result = await queryRunner.manager.getRepository(ChatUserFriend).save(friend);
      // 好友记录
      if (isEmpty(result)) {
        await queryRunner.rollbackTransaction();
        throwHttp('添加失败')
        return
      }
      const userFriend = new ChatUserFriend()
      userFriend.friendsId = friendsId
      userFriend.friends = friends
      userFriend.user = user
      userFriend.userId = userId
      userFriend.status = 2
      userFriend.verification = ''
      userFriend.del = '1'
      userFriend.isRead = 1
      //应用事务保留到副表
      const userFriendResult = await queryRunner.manager.getRepository(ChatUserFriend).save(userFriend);

      // 好友记录
      if (isEmpty(userFriendResult)) {
        await queryRunner.rollbackTransaction();
        throwHttp('添加失败')
        return
      }
      await queryRunner.commitTransaction();
      // 发送消息给好友
      const socketId = this.configService.getChatUser(String(friendsId))
      if (socketId) {
        this.server.in(socketId).emit('getFriendsNotice', { [userId]: 1 });
      }
      return {
        message: '添加成功',
        success: true,
      }
    } catch (error) {
      // 出错回滚
      console.log('创立失败，勾销事务');
      await queryRunner.rollbackTransaction();
      throwHttp(error.message)
    } finally {
      // 开释
      await queryRunner.release();
    }
  }
  /** 更新好友状态 */
  @UseFilters(new HttpExceptionFilter())
  async updateChatUserFriendsStatus(params: AddChatUserFriendsDto) {
    try {
      // 有bug，第二次添加则会通过
      const { userId, friendsId } = params
      let friendsStatus = null
      const where = { userId, friendsId }
      const { status } = await this.getFriendsInfo({ userId, friendsId })
      // 如好友已添加但用户未同意则直接通过申请，更新状态
      if (equals(status, 0)) {
        friendsStatus = 1
        where.friendsId = userId
        where.userId = friendsId
      }
      // 如用户之前已拒绝，则开启申请
      if (equals(status, 2)) {
        friendsStatus = 0
        where.friendsId = userId
        where.userId = friendsId
      }
      await this.chatUserFriendRepository
        .createQueryBuilder()
        .update(ChatUserFriend)
        .set({ status: friendsStatus })
        .where(where)
        .execute();
      return {
        message: '添加成功',
        success: true,
      }
    } catch (error) {

    }
  }
  @UseFilters(new HttpExceptionFilter())
  async applyForVerification(params: ApplyForVerificationDto): Promise<string> {
    try {
      const { friendsId, userId, status, id } = params
      // 查询发起添加好友用户信息
      await this.chatUserService.getUserInfo({ id: friendsId })
      await this.chatUserService.getUserInfo({ id: userId })
      const friendData = await this.chatUserFriendRepository.findOne({
        where: { id },
      })
      if (isNil(friendData) || !equals(friendData.status, 0)) {
        throwHttp('查询不到好友验证信息')
        return
      }
      // 查询是否有添加好友，防止重复请求
      if (!isNil(friendData) && equals(friendData.status, 1)) {
        throwHttp('该好友已添加')
        return
      }
      // 更新当前发起用户好友数据状态
      const { affected } = await this.updateFriends({ userId, friendsId }, {
        isRead: 1,
        status,
      })
      if (!affected) {
        throwHttp('好友验证失败')
        return
      }
      // 更新添加好友的用户
      if (equals(status, 1)) {
        // 更新当前发起用户好友数据状态
        await this.updateFriends({ userId: friendsId, friendsId: userId }, {
          isRead: 1,
          status,
        })
      }
      // 通知好友
      const socketId = this.configService.getChatUser(String(friendsId))
      if (socketId) {
        const chatUserFriend = await this.chatUserFriendRepository.findOne({
          where: { userId: friendsId, friendsId: userId },
        })
        this.server.in(socketId).emit('applyForVerification', { userId: friendsId, friendsId: userId, status, id: chatUserFriend?.id });
        this.server.in(socketId).emit('getContacts');
      }
      return equals(status, 1) ? '通过好友验证' : '拒绝好友验证'
    } catch (error) {
      throw new HttpException(
        {
          status: HttpStatus.BAD_REQUEST,
          message: error.message,
        },
        HttpStatus.BAD_REQUEST,
      )
    }
  }
  // 删除好友
  // 删除好友需将聊天记录更换已读
  // 删除历史会话
  @UseFilters(new HttpExceptionFilter())
  async delChatUserFriends(parmas: DelChatUserFriendsDto): Promise<string> {
    // 获取连贯并创立新的queryRunner
    const queryRunner = this.connection.createQueryRunner();
    // 应用咱们的新queryRunner建设真正的数据库连
    await queryRunner.connect();
    // 开始事务
    await queryRunner.startTransaction();
    try {
      const { friendsId, userId } = parmas
      const useData = await this.getFriendsInfo({ friendsId, userId })
      const friendDatas = await this.getFriendsInfo({ friendsId: userId, userId: friendsId })
      // // 删除用户好友数据
      await queryRunner.manager.getRepository(ChatUserFriend).remove(useData)
      // // 删除好友数据
      await queryRunner.manager.getRepository(ChatUserFriend).remove(friendDatas)
      // 更新聊天记录
      await queryRunner.manager.getRepository(UserChatRecord).createQueryBuilder().update(UserChatRecord).set({
        isRead: 1,
      }).where([{ to_userId: friendsId, userId }, { to_userId: userId, userId: friendsId }]).execute()
      // 删除聊天会话
      const userHistorySession = await queryRunner.manager.getRepository(HistorySession).findOne({ where: { userId, historicalUserSessionsId: String(friendsId) } })
      const friendHistorySession = await queryRunner.manager.getRepository(HistorySession).findOne({ where: { userId: friendsId, historicalUserSessionsId: String(userId) } })
      // 判断是否有历史会话记录
      if (userHistorySession) {
        await queryRunner.manager.getRepository(HistorySession).remove(userHistorySession)
      }
      if (friendHistorySession) {
        await queryRunner.manager.getRepository(HistorySession).remove(friendHistorySession)
      }
      await queryRunner.commitTransaction();
      // 通知好友
      const socketId = this.configService.getChatUser(String(friendsId))
      if (socketId) {
        this.server.in(socketId).emit('getContacts');
      }
      return '删除成功'
    } catch (error) {
      // 出错回滚
      console.log('创立失败，勾销事务');
      await queryRunner.rollbackTransaction();
      throwHttp(error.message)
    } finally {
      // 开释
      await queryRunner.release();
    }
  }

  // 更新好友最新消息
  @UseFilters(new HttpExceptionFilter())
  async updateFriendsLatestNews(params: DelChatUserFriendsDto, userChatRecord: UserChatRecord) {
    try {
      const { userId, friendsId } = params
      await this.chatUserService.getUserInfo({ id: userId })
      await this.chatUserService.getUserInfo({ id: friendsId })
      // 更新用户
      await this.chatUserFriendRepository
        .createQueryBuilder()
        .update(ChatUserFriend)
        .set({ latestNewsId: userChatRecord.id })
        .where({ userId, friendsId })
        .execute();
      // 更新好友信息
      await this.chatUserFriendRepository
        .createQueryBuilder()
        .update(ChatUserFriend)
        .set({ latestNewsId: userChatRecord.id })
        .where({ userId: friendsId, friendsId: userId })
        .execute();
      return '更新成功'
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 获取好友信息
  @UseFilters(new HttpExceptionFilter())
  async getFriendsInfo(params: DelChatUserFriendsDto): Promise<ChatUserFriend> {
    try {
      const { userId, friendsId } = params
      const data = await this.chatUserFriendRepository.findOne({
        where: { userId, friendsId, del: '1' },
      })
      if (isNil(data)) {
        throwHttp('用户不存在')
        return
      }
      return data
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 更新备注
  @UseFilters(new HttpExceptionFilter())
  async updateRemarks(params: UpdateRemarksDto) {
    try {
      const { userId, friendsId, remarks } = params
      // 验证当前好友信息是否存在
      await this.getFriendsInfo({ userId, friendsId, status: 1 })
      // 更新用户
      await this.chatUserFriendRepository
        .createQueryBuilder()
        .update(ChatUserFriend)
        .set({ remarks })
        .where({ userId, friendsId })
        .execute();
      // 更新好友信息
      return '更新成功'
    } catch (error) {
      console.log(error.message);
      throwHttp(error.message)
    }
  }
  /**
   * 删除好友验证
   * @param params DeleteFriendsVerificationDto
   * @returns {string}
   */
  @UseFilters(new HttpExceptionFilter())
  async deleteFriendsVerification(params: DeleteFriendsVerificationDto) {
    try {
      const { userId, friendsId } = params
      // 验证当前好友信息是否存在
      await this.getFriendsInfo({ userId, friendsId })
      // 更新用户
      await this.chatUserFriendRepository
        .createQueryBuilder()
        .update(ChatUserFriend)
        .set({ del: '0' })
        .where({ userId, friendsId })
        .execute();
      // 更新好友信息
      return '更新成功'
    } catch (error) {
      throwHttp(error.message)
    }
  }
  /**
   * 更新好友信息
   */
  async updateFriends({ userId, friendsId }, parmas) {
    try {
      return await this.chatUserFriendRepository
        .createQueryBuilder()
        .update('chat_user_friends')
        .set(parmas)
        .where({ userId, friendsId })
        .execute()
    } catch (error) {
      throwHttp(error.message)
    }
  }
}
